package com.codeanalysissys.backend.ruby;
import com.codeanalysissys.backend.ruby.parser.RubyParserBaseVisitor;
import com.codeanalysissys.backend.ruby.parser.RubyLexer;
import com.codeanalysissys.backend.ruby.parser.RubyParser;

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;

public class RubyClassExtractor {
    public static List<RubyClass> extractInfo(String rubyFile) throws IOException {
        return extractInfo(new File(rubyFile));
    }

    public static List<RubyClass> extractInfo(File rubyFile) throws IOException {
        return extractInfo(rubyFile.getAbsolutePath(), CharStreams.fromPath(Paths.get(rubyFile.getAbsolutePath())));
    }

    public static List<RubyClass> extractInfo(String rubyFilePath, CharStream input) throws IOException {
        RubyLexer lexer = new RubyLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        RubyParser parser = new RubyParser(tokens);
        ParseTree tree = parser.compilation_unit();
        return extractInfo(rubyFilePath, tree);
    }

    public static List<RubyClass> extractInfo(ParseTree tree) {
        rubyClassVisitor visitor = new rubyClassVisitor();
        return visitor.build(tree);
    }

    public static List<RubyClass> extractInfo(String rubyFilePath, ParseTree tree) {
        rubyClassVisitor visitor = new rubyClassVisitor(rubyFilePath);
        return visitor.build(tree);
    }


    private static int countSlashes(String str) {
        int slashCount = 0;
        for (char chr : str.toCharArray())
            if (chr == '/')
                ++slashCount;
        return slashCount;
    }

    private static class rubyClassVisitor extends RubyParserBaseVisitor<String> {

        private String filePath;
        private int methodNumNoClass = 0;
        private List<String> importsList;
        ArrayList<String> impList;
        private String Modifier;
        private List<RubyClass> RubyClasses;
        private String expr;
        private Deque<RubyClass> activeClasses;
        private boolean Done;

        public rubyClassVisitor(String path) {
            filePath = path;
        }

        public rubyClassVisitor() {
            filePath = null;
        }

        public List<RubyClass> build(ParseTree tree) {
            Modifier = "public";
            impList = new ArrayList<>();
            RubyClasses = new ArrayList<>();
            importsList = new ArrayList<>();
            activeClasses = new ArrayDeque<>();
            Done = false;
            visit(tree);
//            if(!activeClasses.isEmpty()) {
//                rubyClasses.add(activeClasses.pop());
//            }
            return RubyClasses;
        }
        @Override
        public String visitImports(RubyParser.ImportsContext ctx) {
            String qualifiedName = ctx.getText();
            importsList.add(qualifiedName);
            return null;
        }
        @Override
        public String visitClass_definition(RubyParser.Class_definitionContext ctx)
        {
            String extend = null;
            if(ctx.class_header().BIT_SHL()!=null)
                return null;
            if (ctx.class_header().superclass()!= null)
                extend =ctx.class_header().superclass().id_symbol().getText();
//            visit(ctx.statement_list_terms());
            RubyClass rls = new RubyClass(ctx.class_header().cpath().getText(), filePath, extend);
            activeClasses.push(rls);
            visit(ctx.statement_list_terms());
            RubyClasses.add(activeClasses.pop());
            return null;
        }
//        @Override
//        public String visitStatement_list_terms(RubyParser.Statement_list_termsContext ctx)
//        {
//            visitChildren(ctx);
//            if(!Done)
//            {
//                if(ctx.statement()!=null) {
//                    expr += ctx.statement().getText();
//                    if (ctx.terms().term().isEmpty()) {
//                        expr += " ";
//                    } else {
//                        if(!expr.contains("\"")&&!expr.contains("'")) {
//                            if (expr.contains("include")) {
//                                String tmp = expr.replace("include", "").trim();
//                                impList.add(tmp);
//                            }
//                            else if(expr.contains("public"))
//                            {
//                                Modifier="public";
//                            }
//                            else if(expr.contains("private"))
//                            {
//
//                            }
//                        }
//                        expr = "";
//                    }
//                }
//            }
//            else
//                Done=false;
//            return null;
//        }
//        public String expNode(RubyParser.Statement_list_termsContext ctx)
//        {
//            if(!expr.equals("")) {
//                if(!expr.contains("\"")&&!expr.contains("'")) {
//                    if (expr.contains("include")) {
//                        String tmp = expr.replace("include", "").trim();
//                        impList.add(tmp);
//                    }
//                }
//                expr="";
//            }
//            return null;
//        }
        @Override
        public String visitExprInclude(RubyParser.ExprIncludeContext ctx)
        {
            activeClasses.peek().addimplements(ctx.primary().getText());
            return null;
        }
        @Override
        public String visitPrimaryModifier(RubyParser.PrimaryModifierContext ctx)
        {
            Modifier=ctx.getText();
            return null;
        }
        @Override
        public String visitFunction_definition(RubyParser.Function_definitionContext ctx)
        {
            String retType = "auto";
            if (ctx.function_definition_header().expr() != null) {
                retType = ctx.function_definition_header().expr().getText();
                retType=retType.replace("->","");
            }
            String name = ctx.function_definition_header().function_name().getText();
            String[] args = null;
            List<String> argsList = new ArrayList<>();
            if (ctx.function_definition_header().function_definition_params() != null) {
                for (int i=0;i<ctx.function_definition_header().function_definition_params().function_definition_param().size();i++) {
                    argsList.add(ctx.function_definition_header().function_definition_params().function_definition_param(i).getText());
                }
            }
            if (argsList.size() > 0)
                args = argsList.toArray(new String[argsList.size()]);
            else
                args = argsList.toArray(new String[0]);
            int line = ctx.getStart().getLine();
            if(!activeClasses.isEmpty())
                activeClasses.peek().addMethod(new Rubymethod(Modifier, name, args, retType, line));
            return null;
        }
    }
}
